package com.example.jflow.com;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * RSA加解密工具
 * @author pyx
 * @date 2023/6/11
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RSAUtils {
    private static final String RSA_ALGORITHM = "RSA";

    /**
     * 通用解密方法，先对密文先进行base64转码，再分别获取密钥和密文，最后进行解密
     *
     * @param privateKey 解密用的私钥
     * @param plaintext  需要解密的字符串
     * @return
     * @Date 2023/4/18
     */
    public static String decrypt(final byte[] privateKey, final byte[] plaintext) {
        try {
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            PrivateKey key = keyFactory.generatePrivate(keySpec);
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(cipher.doFinal(plaintext));
        } catch (Exception exception) {
            log.error("RSA解密失败", exception);
            throw new RuntimeException("RSA解密失败");
        }
    }

    /**
     * 通用加密方法，应返回base64(密钥,密文)，用于替换应用application.properties中使用通用加密方案的密码
     *
     * @param publicKey 加密的公钥
     * @param plaintext 待加密的字段
     * @return
     * @Date 2023/4/18
     */
    public static String encrypt(final byte[] publicKey, final byte[] plaintext) {
        try {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            PublicKey key = keyFactory.generatePublic(keySpec);
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return Base64.encodeBase64URLSafeString(cipher.doFinal(plaintext));
        } catch (Exception exception) {
            log.error("RSA加密失败", exception);
            throw new RuntimeException("RSA解密失败");
        }
    }
}
